{
 "cells": [
  {
   "cell_type": "code",
   "id": "initial_id",
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "end_time": "2025-03-05T01:27:00.907766Z",
     "start_time": "2025-03-05T01:26:57.910696Z"
    }
   },
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "\n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.0\n",
      "torch 2.3.1+cu121\n",
      "cuda:0\n"
     ]
    }
   ],
   "execution_count": 1
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:27:01.861379Z",
     "start_time": "2025-03-05T01:27:00.908393Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# Path: 用于处理文件路径。\n",
    "from pathlib import Path\n",
    "\n",
    "# 定义数据集的根目录为 ./cifar-10/\n",
    "# 使用 Path 对象处理文件路径\n",
    "DATA_DIR = Path(\"./cifar-10\")\n",
    "\n",
    "train_lables_file = DATA_DIR / \"trainLabels.csv\"  # 训练集标签csv文件\n",
    "test_csv_file = DATA_DIR / \"sampleSubmission.csv\"  #测试集模板csv文件\n",
    "train_folder = DATA_DIR / \"train\"  # 训练集图片文件夹\n",
    "test_folder = DATA_DIR / \"test\"  # 测试集图片文件夹\n",
    "\n",
    "#所有的类别\n",
    "class_names = [\n",
    "    'airplane',\n",
    "    'automobile',\n",
    "    'bird',\n",
    "    'cat',\n",
    "    'deer',\n",
    "    'dog',\n",
    "    'frog',\n",
    "    'horse',\n",
    "    'ship',\n",
    "    'truck',\n",
    "]\n",
    "\n",
    "\n",
    "# 定义一个函数 parse_csv_file，用于解析 CSV 文件并返回图像路径和标签的列表\n",
    "# filepath: CSV 文件的路径。\n",
    "# folder: 图像文件夹的路径\n",
    "# 读取 CSV 文件，解析每一行，生成图像路径和标签的元组列表\n",
    "def parse_csv_file(filepath, folder):\n",
    "    # 初始化一个空列表 results，用于存储解析结果\n",
    "    # 使用列表存储图像路径和标签的元组,方便后续访问和操作解析结果\n",
    "    results = []\n",
    "\n",
    "    # 打开 CSV 文件，读取所有行并跳过第一行（表头）\n",
    "    # 使用 open 函数打开文件，readlines() 读取所有行，[1:] 跳过表头\n",
    "    with open(filepath, 'r') as f:\n",
    "        lines = f.readlines()[1:]\n",
    "\n",
    "    # 遍历每一行数据，去除换行符并按逗号分隔，得到图像 ID 和标签\n",
    "    # 使用 strip('\\n') 去除换行符，split(',') 按逗号分隔,提取图像 ID 和标签\n",
    "    for line in lines:\n",
    "        image_id, label_str = line.strip('\\n').split(',')\n",
    "\n",
    "        # 拼接图像文件的完整路径\n",
    "        # 使用 Path 对象拼接路径，f\"{image_id}.png\" 生成图像文件名\n",
    "        image_full_path = folder / f\"{image_id}.png\"\n",
    "\n",
    "        # 将图像路径和标签的元组添加到 results 列表中\n",
    "        results.append((image_full_path, label_str))\n",
    "    return results\n",
    "\n",
    "\n",
    "#  调用 parse_csv_file 函数，解析训练集和测试集的 CSV 文件\n",
    "train_labels_info = parse_csv_file(train_lables_file, train_folder)\n",
    "test_csv_info = parse_csv_file(test_csv_file, test_folder)\n",
    "\n"
   ],
   "id": "802a22548a5f33cb",
   "outputs": [],
   "execution_count": 2
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:27:01.892525Z",
     "start_time": "2025-03-05T01:27:01.862396Z"
    }
   },
   "cell_type": "code",
   "source": [
    "train_df = pd.DataFrame(train_labels_info[0:45000])  # 取前45000张图片作为训练集\n",
    "valid_df = pd.DataFrame(train_labels_info[45000:])  # 取后5000张图片作为验证集\n",
    "test_df = pd.DataFrame(test_csv_info)  # 取测试集\n",
    "\n",
    "train_df.columns = ['filepath', 'class']  # 给数据框添加列名\n",
    "valid_df.columns = ['filepath', 'class']\n",
    "test_df.columns = ['filepath', 'class']  # 数据准备"
   ],
   "id": "be5475f09cba3b29",
   "outputs": [],
   "execution_count": 3
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:27:02.937101Z",
     "start_time": "2025-03-05T01:27:01.893535Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# PIL（Python Imaging Library）用于图像处理，Image 模块可以加载和操作图像\n",
    "from PIL import Image\n",
    "\n",
    "# Dataset 是 PyTorch 中用于定义数据集的基类\n",
    "# DataLoader 用于批量加载数据，支持多线程和数据打乱\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "# transforms 提供了图像预处理和数据增强的工具，如调整大小、旋转、归一化等\n",
    "from torchvision import transforms\n",
    "\n",
    "\n",
    "# 定义一个自定义数据集类，继承自 PyTorch 的 Dataset 类\n",
    "# CIFAR-10 数据集的加载方式与默认数据集不同，需要自定义\n",
    "class Cifar10Dataset(Dataset):\n",
    "    # 定义一个字典，将数据集模式（train/eval/test）映射到对应的数据框\n",
    "    # 通过 mode 参数快速获取对应的数据集\n",
    "    df_map = {\n",
    "        \"train\": train_df,\n",
    "        \"eval\": valid_df,\n",
    "        \"test\": test_df\n",
    "    }\n",
    "\n",
    "    # 创建一个字典，将类别名称映射到索引（如 \"cat\" -> 0）\n",
    "    # 使用字典推导式生成映射关系\n",
    "    # 模型需要数值标签，而数据通常以类别名称存储，因此需要转换\n",
    "    label_to_idx = {label: idx for idx, label in enumerate(class_names)}\n",
    "\n",
    "    # 创建一个字典，将索引映射回类别名称（如 0 -> \"cat\"）\n",
    "    # 与 label_to_idx 类似，但方向相反\n",
    "    # 在模型预测后，可能需要将索引转换回类别名称以便解释结果\n",
    "    idx_to_label = {idx: label for idx, label in enumerate(class_names)}\n",
    "\n",
    "    # 初始化 Cifar10Dataset 类的实例\n",
    "    # mode：指定数据集模式（train/eval/test）。\n",
    "    # transform：指定图像预处理和数据增强的方法\n",
    "    def __init__(self, mode, transform=None):\n",
    "        # 根据 mode 获取对应的数据框\n",
    "        # 使用字典的 get 方法获取值，如果 mode 不存在则返回 None\n",
    "        self.df = self.df_map.get(mode, None)\n",
    "\n",
    "        # 检查 mode 是否有效，如果无效则抛出错误\n",
    "        # 防止因无效模式导致后续代码出错\n",
    "        if self.df is None:\n",
    "            raise ValueError(\"mode should be one of train, val, test, but got {}\".format(mode))\n",
    "\n",
    "        # 保存 transform 参数到对象属性中\n",
    "        # 在 __getitem__ 方法中会用到 transform\n",
    "        self.transform = transform\n",
    "\n",
    "    # 根据索引获取单个样本（图像和标签）\n",
    "    # Dataset 类的核心方法，定义了如何获取数据,DataLoader 会调用此方法批量加载数据\n",
    "    def __getitem__(self, index):\n",
    "        # 从数据框中获取图像路径和标签\n",
    "        # 使用 iloc 方法按索引获取数据,数据框存储了图像路径和标签，需要按索引提取\n",
    "        img_path, label = self.df.iloc[index]\n",
    "\n",
    "        # 加载图像并转换为 RGB 格式\n",
    "        # Image.open 加载图像，convert('RGB') 确保图像为三通道\n",
    "        img = Image.open(img_path).convert('RGB')\n",
    "\n",
    "        # 对图像应用预处理和数据增强\n",
    "        img = self.transform(img)\n",
    "\n",
    "        # 将类别名称转换为索引,使用 label_to_idx 字典进行转换\n",
    "        label = self.label_to_idx[label]\n",
    "        return img, label\n",
    "\n",
    "    def __len__(self):\n",
    "        # 返回数据框的行数，即样本数量\n",
    "        # shape[0] 获取数据框的行数\n",
    "        return self.df.shape[0]\n",
    "\n",
    "\n",
    "# 定义图像的输入大小\n",
    "IMAGE_SIZE = 32\n",
    "mean, std = [0.4368, 0.4268, 0.3947], [0.2464, 0.2418, 0.2358]\n",
    "\n",
    "# 定义训练数据的预处理和数据增强方法\n",
    "# 数据增强（如旋转、翻转）可以提高模型的泛化能力，避免过拟合\n",
    "# 训练时需要增加数据的多样性，同时确保输入数据符合模型的期望格式\n",
    "transforms_train = transforms.Compose([\n",
    "    transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),  # 将图像调整为指定大小（32x32）\n",
    "    transforms.RandomRotation(40),  # 随机旋转图像，最大角度为40度\n",
    "    transforms.RandomHorizontalFlip(),  # 随机水平翻转图像\n",
    "    transforms.ToTensor(),  # 将图像转换为PyTorch张量（Tensor），并将像素值从 [0, 255] 归一化到 [0, 1]。\n",
    "    transforms.Normalize(mean, std)  # 根据均值和标准差对图像进行归一化\n",
    "])\n",
    "\n",
    "# 验证/测试数据不需要数据增强，只需进行基本的预处理\n",
    "# 验证/测试时，需要保持数据的原始分布，以评估模型的真实性能\n",
    "transforms_eval = transforms.Compose([\n",
    "    transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),  # 将图像调整为指定大小（32x32）\n",
    "    transforms.ToTensor(),  # 将图像转换为PyTorch张量（Tensor），并将像素值从 [0, 255] 归一化到 [0, 1]。\n",
    "    transforms.Normalize(mean, std)  # 根据均值和标准差对图像进行归一化\n",
    "])\n",
    "\n",
    "# 创建训练数据集对象\n",
    "train_ds = Cifar10Dataset(\"train\", transforms_train)\n",
    "eval_ds = Cifar10Dataset(\"eval\", transforms_eval)"
   ],
   "id": "3506da117fa00681",
   "outputs": [],
   "execution_count": 4
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:27:02.942484Z",
     "start_time": "2025-03-05T01:27:02.938108Z"
    }
   },
   "cell_type": "code",
   "source": [
    "batch_size = 64\n",
    "train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True)\n",
    "eval_dl = DataLoader(eval_ds, batch_size=batch_size, shuffle=False)"
   ],
   "id": "aaa2c03a49d8ec19",
   "outputs": [],
   "execution_count": 5
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 定义模型",
   "id": "42d76a8fb4b3371f"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:27:02.950490Z",
     "start_time": "2025-03-05T01:27:02.943490Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class VGG(nn.Module):\n",
    "    def __init__(self, num_classes):\n",
    "        super().__init__()\n",
    "        self.model = nn.Sequential(\n",
    "            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=\"same\"),  # 32*32*32\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),  # 32*32*32\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),  # 32*16*16\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),  # 32*16*16\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),  # 32*8*8\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),  # 32*8*8\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(kernel_size=2),  # 32*4*4\n",
    "            nn.Flatten(),\n",
    "            nn.Linear(512, num_classes),\n",
    "        )\n",
    "        self.init_weights()\n",
    "\n",
    "    def init_weights(self):\n",
    "        \"\"\"使用 xavier 均匀分布来初始化全连接层、卷积层的权重 W\"\"\"\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, (nn.Linear, nn.Conv2d)):  # 全连接层、卷积层\n",
    "                nn.init.kaiming_uniform_(m.weight, mode='fan_in', nonlinearity='relu')\n",
    "                # 采用kaiming_uniform初始化权重, mode='fan_in'表示权重初始化为均匀分布，nonlinearity='relu'表示激活函数为relu\n",
    "                if m.bias is not None:\n",
    "                    nn.init.constant_(m.bias, 0.01)  # 偏置初始化为常数值，比如0.01\n",
    "\n",
    "    def forward(self, x):\n",
    "        return self.model(x)\n",
    "\n",
    "\n",
    "for key, value in VGG(len(class_names)).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")"
   ],
   "id": "70a51718993722ac",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "             model.0.weight             paramerters num: 864\n",
      "              model.0.bias              paramerters num: 32\n",
      "             model.2.weight             paramerters num: 9216\n",
      "              model.2.bias              paramerters num: 32\n",
      "             model.5.weight             paramerters num: 9216\n",
      "              model.5.bias              paramerters num: 32\n",
      "             model.7.weight             paramerters num: 9216\n",
      "              model.7.bias              paramerters num: 32\n",
      "            model.10.weight             paramerters num: 9216\n",
      "             model.10.bias              paramerters num: 32\n",
      "            model.12.weight             paramerters num: 9216\n",
      "             model.12.bias              paramerters num: 32\n",
      "            model.16.weight             paramerters num: 5120\n",
      "             model.16.bias              paramerters num: 10\n"
     ]
    }
   ],
   "execution_count": 6
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 训练",
   "id": "47228962df9cf1da"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:27:02.991192Z",
     "start_time": "2025-03-05T01:27:02.950996Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)  # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "\n",
    "        preds = logits.argmax(axis=-1)  # 验证集预测\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "\n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc\n"
   ],
   "id": "2fee643abba219f3",
   "outputs": [],
   "execution_count": 7
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:27:06.740246Z",
     "start_time": "2025-03-05T01:27:02.992209Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "\n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\",\n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "        )\n",
    "\n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "\n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "\n",
    "        )\n",
    "\n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ],
   "id": "9a4e94c374f556cf",
   "outputs": [],
   "execution_count": 8
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:27:06.746259Z",
     "start_time": "2025-03-05T01:27:06.740246Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "\n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "\n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "\n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ],
   "id": "766348b53e8fe7c8",
   "outputs": [],
   "execution_count": 9
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:27:06.754849Z",
     "start_time": "2025-03-05T01:27:06.747764Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "\n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else:\n",
    "            self.counter += 1\n",
    "\n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ],
   "id": "72404ef19634ce69",
   "outputs": [],
   "execution_count": 10
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:33:16.887959Z",
     "start_time": "2025-03-05T01:27:06.755853Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 训练\n",
    "def training(\n",
    "        model,\n",
    "        train_loader,\n",
    "        val_loader,\n",
    "        epoch,\n",
    "        loss_fct,\n",
    "        optimizer,\n",
    "        tensorboard_callback=None,\n",
    "        save_ckpt_callback=None,\n",
    "        early_stop_callback=None,\n",
    "        eval_step=500,\n",
    "):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "\n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits.argmax(axis=-1)\n",
    "\n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())\n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "\n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
    "                })\n",
    "\n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "\n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step,\n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            acc=acc, val_acc=val_acc,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                        )\n",
    "\n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "\n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "\n",
    "    return record_dict\n",
    "\n",
    "\n",
    "epoch = 10\n",
    "\n",
    "model = VGG(num_classes=10)\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失\n",
    "loss_fct = nn.CrossEntropyLoss()\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package,可以修改beta1,beta2,weight_decay等参数\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999))\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "tensorboard_callback = TensorBoardCallback(\"runs/vgg\")\n",
    "tensorboard_callback.draw_model(model, [1, 3, IMAGE_SIZE, IMAGE_SIZE])\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/vgg\", save_step=len(train_dl), save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=5)\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model,\n",
    "    train_dl,\n",
    "    eval_dl,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    ")"
   ],
   "id": "39bfc946de0774c0",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/7040 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "9e2deb066eb24c64b2b491b28cb9c30e"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 11
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:33:17.052163Z",
     "start_time": "2025-03-05T01:33:16.889963Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):\n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "plot_learning_curves(record, sample_step=100)  #横坐标是 steps"
   ],
   "id": "73752b0918d320a5",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 12
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 评估",
   "id": "e6b5ed4846032607"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:33:19.686104Z",
     "start_time": "2025-03-05T01:33:17.053180Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# dataload for evaluating\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(\"checkpoints/vgg/best.ckpt\", map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, eval_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ],
   "id": "2348d53449575777",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.9240\n",
      "accuracy: 0.6750\n"
     ]
    }
   ],
   "execution_count": 13
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-05T01:33:19.689456Z",
     "start_time": "2025-03-05T01:33:19.687207Z"
    }
   },
   "cell_type": "code",
   "source": "",
   "id": "ec5ea2d1a5572b80",
   "outputs": [],
   "execution_count": 13
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
